/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { BaseButtonlessDfuImpl } from './BaseButtonlessDfuImpl'
import { LegacyDfuImpl } from './LegacyDfuImpl'
import { DfuBaseService } from './DfuBaseService'
import ble from '@ohos.bluetooth.ble';
import hilog from '@ohos.hilog';

export class LegacyButtonlessDfuImpl extends BaseButtonlessDfuImpl {
  // UUIDs used by the DFU
  static DFU_SERVICE_UUID: string = LegacyDfuImpl.DEFAULT_DFU_SERVICE_UUID;
  static DFU_CONTROL_POINT_UUID: string = LegacyDfuImpl.DEFAULT_DFU_CONTROL_POINT_UUID;
  static DFU_VERSION_UUID: string = LegacyDfuImpl.DEFAULT_DFU_VERSION_UUID;

  private static OP_CODE_ENTER_BOOTLOADER: Uint8Array = new Uint8Array([0x01, 0x04]);

  private mControlPointCharacteristic: ble.BLECharacteristic;
  private mVersion: number;

  constructor(service: DfuBaseService) {
    super(service);
    this.TAG = 'LegacyButtonlessDfuImpl';
  }

  public shouldScanForBootloader(): boolean {
    return false;
  }

  public finalize(forceRefresh: boolean, scanForBootloader: boolean) {

  };

  protected getDfuServiceUUID(): string {
    return LegacyButtonlessDfuImpl.DFU_SERVICE_UUID;
  }

  public async isClientCompatible(gattServiceList: Array<ble.GattService>): Promise<boolean> {
    hilog.info(this.DOMAIN, this.TAG, 'LegacyButtonlessDfuImpl isClientCompatible');
    //TODO: find service with spec UUID
    for (const gsItem of gattServiceList) {
      hilog.info(this.DOMAIN, this.TAG, `LegacyButtonlessDfuImpl ${gsItem.serviceUuid}`);
      if (gsItem.serviceUuid === LegacyButtonlessDfuImpl.DFU_SERVICE_UUID) {
        for (const gcItem of gsItem.characteristics) {
          if (gcItem.characteristicUuid === LegacyButtonlessDfuImpl.DFU_CONTROL_POINT_UUID) {
            for (const gdItem of gcItem.descriptors) {
              if (gdItem.descriptorUuid === LegacyButtonlessDfuImpl.CLIENT_CHARACTERISTIC_CONFIG.toUpperCase()) {
                hilog.info(this.DOMAIN, this.TAG, 'Is LegacyButtonlessDfuImpl Client');
                this.mControlPointCharacteristic = gcItem;
                this.mProgressInfo.setProgress(DfuBaseService.PROGRESS_STARTING);

                // TODO: check version characteristic
                for (const gcItem2 of gsItem.characteristics) {
                  if (gcItem2.characteristicUuid === LegacyButtonlessDfuImpl.DFU_VERSION_UUID) {
                    let verGC = await this.mGatt.readCharacteristicValue(gcItem2);
                    let gcValue = new Uint8Array(verGC.characteristicValue);
                    hilog.info(this.DOMAIN, this.TAG,
                      `version value: ${JSON.stringify(gcValue)} ${this.getVersionFeatures(gcValue[0])}`)

                    // TODO: In case of old DFU bootloader versions, In case of 3 service
                    // it will start the DFU procedure (Generic Access, Generic Attribute, DFU Service).
                    // If more services will be found, it assumes that a jump to the DFU bootloader is required.
                    return gcValue[0] === 1 || ( gcValue[0] === 0 && gattServiceList.length > 3);
                  }
                }
                return gattServiceList.length > 3;
              }
            }
          }
        }
      }
    }
    return false;
  }

  public performDfu() {
    hilog.info(this.DOMAIN, this.TAG, 'LegacyButtonlessDfuImpl performDfu')
  }

  private getVersionFeatures(version: number): string {
    switch (version) {
      case 0:
        return "Bootloader from SDK 6.1 or older";
      case 1:
        return "Application with Legacy buttonless update from SDK 7.0 or newer";
      case 5:
        return "Bootloader from SDK 7.0 or newer. No bond sharing";
      case 6:
        return "Bootloader from SDK 8.0 or newer. Bond sharing supported";
      case 7:
        return "Bootloader from SDK 8.0 or newer. SHA-256 used instead of CRC-16 in the Init Packet";
      case 8:
        return "Bootloader from SDK 9.0 or newer. Signature supported";
      default:
        return "Unknown version";
    }
  }
}